/**
 * execInspect: Test utility to run from a shell. Opens a log file and inspects
 * its environment.
 *  - Checks that argc and argv agree and that argv is correctly formatted
 *  - Finds and identifies all inherited fds (things that forgot to close on exec)
 *  - Accepts and logs any input on stdin
 */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdarg.h>

static void logPrintf(const char *fmt, ...);

int logfd;

int main(int argc, char **argv)
{
	logfd = open("execinspect.log", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
	if(logfd<0)
		return 1;
	
	logPrintf("execinspect started\n");
	
	// Verify that argv is null terminated to the length indicated by argc
	for(int ii=0; ii<argc; ii++) {
		if(!argv[ii])
			logPrintf("WARNING: argv[%i] is null when it shouldn't be\n", ii);
	}
	if(argv[argc])
		logPrintf("WARNING: argv[argc] is non-null when it shouldn't be\n");
	
	// Log the arguments
	logPrintf("argc=%i; argv={", argc);
	for(int ii=0; ii<argc; ii++) {
		if(ii) logPrintf(", ");
		logPrintf("\"%s\"", argv[ii]);
	}
	logPrintf("}\n");
	
	// Check file descriptors
	struct stat buf;
	for(int ii=0; ii<64; ii++)
	{
		if(fstat(ii, &buf) < 0)
			continue;
		
		const char *fileType;
		switch (buf.st_mode & S_IFMT)
		{
			case S_IFBLK:  fileType = "block device";     break;
			case S_IFCHR:  fileType = "character device"; break;
			case S_IFDIR:  fileType = "directory";        break;
			case S_IFIFO:  fileType = "FIFO/pipe";        break;
			case S_IFLNK:  fileType = "symlink";          break;
			case S_IFREG:  fileType = "regular file";     break;
			case S_IFSOCK: fileType = "socket";           break;
			default:       fileType = "unknown?";         break;
		}
		
		if(ii==logfd)
			fileType = "log file";
		
		logPrintf("Open fd %i: %s\n", ii, fileType);
	}
	
	return 0;
}

static void logPrintf(const char *fmt, ...)
{
	char buf[1024];
	
	va_list list;
	va_start(list, fmt);
	vsnprintf(buf, 1024, fmt, list);
	va_end(list);
	
	char *writePos = buf;
	int writeLen = strlen(buf);
	
	while(writeLen > 0)
	{
		int bytesWritten = write(logfd, writePos, writeLen);
		writePos += bytesWritten;
		writeLen -= bytesWritten;
	}
}

